package cn.javadog.cloud.starter.limiter.interceptor;

import cn.javadog.cloud.starter.limiter.annotation.AccessLimit;
import cn.javadog.cloud.starter.limiter.config.LimiterProperties;
import cn.javadog.cloud.starter.limiter.exception.LimiterException;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import java.security.Principal;
import java.util.concurrent.TimeUnit;


/**
 * @author yuy
 *
 * 切面
 */
@Slf4j
@Aspect
public class AccessLimitAspect {

    private static final String THE_COLON = ":";
    private final String prefix;

    @Resource
    private StringRedisTemplate stringRedisTemplate;

    public AccessLimitAspect(String prefix){
        this.prefix = prefix;
    }

    /**
     * 切入@AccessLimit注解的方法
     */
    @Pointcut("@annotation(cn.javadog.cloud.starter.limiter.annotation.AccessLimit)")
    public void accessLimitPointCut() {
    }

    @Before("accessLimitPointCut() && @annotation(limit)")
    public void requestLimit(AccessLimit limit) throws LimiterException {
        // 参数
        HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.currentRequestAttributes()).getRequest();
        String url = request.getRequestURL().toString();

//        Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
//        String identifier = authentication.getName();
        String identifier = "yuy";

        // 使用redis实现接口限流
        this.checkWithRedis(limit, identifier, url);
    }

    private void checkWithRedis(AccessLimit limit, String identifier, String url) throws LimiterException {
        // 组装key
        String key = prefix.concat(identifier).concat(THE_COLON).concat(url);

        //获取限流参数
        long seconds = limit.seconds();
        int maxCount = limit.maxCount();

        if (seconds > 0 && maxCount > 0) {
            Long count = stringRedisTemplate.opsForValue().increment(key, 1);
            if (count > maxCount) {
                log.warn("用户[{}]在[{}]s内第[{}]次尝试调用接口: [{}], 超过了[{}]次的限制",
                        identifier, seconds, count, url, maxCount);
                throw new LimiterException();
            }

            if (count == 1) {
                stringRedisTemplate.expire(key, seconds, TimeUnit.SECONDS);
            }
        }

    }

}
